<?php
/**
 * Created by PhpStorm.
 * User: ZhangYinxian
 * Date: 2016-09-25
 * Time: 22:46
 */

namespace app\index\logic;


class Amino
{
    public function analyze($checkAmino, $standardData){
        if(count($standardData)==0){
            return array(
                'has_error'=>true,
                'message'=>'可校验的标准数据为空，无法校验'
            );
        }

        if(strlen($checkAmino)==0){
            return array(
                'has_error'=>true,
                'message'=>'需校验的序列字符串为空，无法校验'
            );
        }

        $keys = array_keys($standardData);
        $amino_max_length = 0;
        foreach($keys as $amino_key){
            $amino_max_length = strlen($amino_key)>$amino_max_length ? strlen($amino_key) : $amino_max_length;
        }

        $valid_result = $this->aminoToArray($checkAmino, $standardData, $amino_max_length);
        return $valid_result;
    }
    /**
     * 将amino字符串序列序列转换为数组
     * @param $checkAmino @mixed 需要检查的序列
     */
    private function aminoToArray($checkAmino, $standardData, $aminoMaxLength){
        $standard_data = $standardData;
        $amino_max_length = $aminoMaxLength;

        $result = array();
        $amino_length = strlen($checkAmino);
        $index = 0;

        if(is_null($standard_data) || empty($standard_data)){
            return array(
                'has_error'=>true,
                'message'=>'可校验的标准数据为空，无法校验'
            );
        }

        while($index < $amino_length){
            //当前校验的字符串长度
            $current_amino_length = strlen($checkAmino);

            // 按照标准最长长度去计算子序列
            $sub_length = ($amino_max_length < $current_amino_length) ? $amino_max_length : $current_amino_length;
            $sub_amino_result = $this->getSubAmino($standard_data, $amino_max_length, $checkAmino);

            if(is_null($sub_amino_result)){
                return array(
                    'has_error'=>true,
                    'message'=>'校验错误,未获取正确的子序列结果'
                );
            }

            if($sub_amino_result['has_error']){
                return $sub_amino_result;
            }

            $sub_amino = $sub_amino_result['sub_amino'];

            if(array_key_exists($sub_amino, $standard_data)){
                array_push($result, $sub_amino);
                $sub_amino_length = $sub_amino_result['real_length'];
                $index = $index + $sub_amino_length;
                $checkAmino = substr($checkAmino, $sub_amino_length);
            }
        }
        $valid_result = array(
            'has_error'=>false,
            'message'=>'校验正确',
            'amino_detail'=>$result
        );
        return $valid_result;
    }

    /**
     * 获取正确的子序列
     * 根据data文件中给出的最长序列进行匹配，从长到短直到匹配，若最后未能找到的，则提示错误
     */
    private function getSubAmino($standardData, $aminoMaxLength, $checkAmino){
        $length = strlen($checkAmino);
        $sub_length = ($aminoMaxLength > $length) ? $length : $aminoMaxLength;
        $real_length = $sub_length;

        $tmp_check_amino = $checkAmino;

        if(strpos($tmp_check_amino, '-')===0 && strlen($tmp_check_amino)>0){
            if(array_key_exists($tmp_check_amino, $standardData)){
                return array(
                    'sub_amino'=>$tmp_check_amino,
                    'real_length'=>$real_length,
                    'has_error'=>false,
                    'message'=>'正确匹配'
                );
            }
            // 若以-开头直接去判断，若有则返回，若无，则去除-
            $tmp_check_amino = substr($tmp_check_amino, 1);
            $sub_length--;
        }

        $sub_amino = substr($tmp_check_amino, 0, $sub_length);

        if(array_key_exists($sub_amino, $standardData)){
            return array(
                'sub_amino'=>$sub_amino,
                'real_length'=>$real_length,
                'has_error'=>false,
                'message'=>'正确匹配'
            );
        }else{
            if($aminoMaxLength<=0){
                return array(
                    'has_error'=>true,
                    'message'=>"此段序列：$checkAmino  存在无法识别字符"
                );
            }
            $amino_max_length = $aminoMaxLength - 1;
            return $this->getSubAmino($standardData, $amino_max_length, $checkAmino);
        }
    }
}